<?php
fily_XMLConverter::registerNamespace('page', fily_Page);
class fily_Page implements fily_ControlToHtml, fily_XMLToControl {
    /**
     * css controls list
     * @var fily_ControlList
     */
    protected $CSSControls;
    /**
     * javascript controls list
     * @var fily_ControlList
     */
    protected $JSControls;

    /**
     * metadata controls list
     * @var fily_ControlList
     */
    protected $metaDataControls;

    /**
     * title of the page
     * @var <type>
     */
    protected $title;
    /**
     * head controls
     * @var fily_ControlList
     */
    protected $headControls;
    /**
     * body controls
     * @var fily_ControlList
     */
    public $controls;

    /**
     * path to the javascript file
     * @var string
     */
    protected $javascriptCorePath;

    /**
     *
     */
    public function __construct() {
        $this->CSSControls = new fily_ControlList();
        $this->CSSControls->setParent($this);
        $this->JSControls = new fily_ControlList();
        $this->JSControls->setParent($this);
        $this->headControls = new fily_ControlList();
        $this->headControls->setParent($this);
        $this->metaDataControls = new fily_ControlList();
        $this->metaDataControls->setParent($this);
        $this->controls = new fily_ControlList();
        $this->controls->setParent($this);
        $this->addMetaData(array ('http-equiv' => 'Content-Type', 'content' => 'text/fily_Html; charset=iso-8859-1'));
        $this->addMetaData(array ('http-equiv' => 'Content-Style-Type', 'content' => 'text/css'));

    }


    /**
     * adds a control to the head
     * @param fily_ControlToHtml $control
     */
    public function addToHead(fily_ControlToHtml $control) {
        $this->headControls->add($control);
    }

    /**
     * set the title of the page
     * @param string $value
     */
    public function setTitle($value) {
        $this->title = $value;
    }

    /**
     * add meta data to this page
     * @param array $attributes array of the attributes and values
     */
    public function addMetaData(array $attributes) {
        $metaDataControl = new fily_ControlContainer('meta');
        foreach($attributes as $key => $value) {
            $metaDataControl->attributes->merge($attributes);
        }
        $this->addMetaDataControl($metaDataControl);
    }

    /**
     * adds meta data to this page
     * @param fily_Control $meta
     */
    public function addMetaDataControl(fily_Control $meta) {
        // TODO: delete the old meta fily_Control if exists
        $this->metaDataControls->add($meta);
    }


    /**
     * returns the title of this page
     * @return string
     */
    public function getTitle() {
        return $this->title;
    }



    /**
     * adds a css file to the head
     * @param string $file file path
     */
    public function addCSSFile($file) {
        $firstInclude = true; //it is the first include

        // check if this file is already included
        foreach($this->CSSControls->getItems() as $cssFile) {
            if($cssFile->attributes->get('href') == $file) {
                $firstInclude = false; //already included
            }
        }

        if($firstInclude) {
            $link = new fily_Control('link');
            $link->attributes->set('type', 'text/css');
            $link->attributes->set('rel', 'stylesheet');
            $link->attributes->set('href', $file);
            $this->CSSControls->add($link);
        }
    }

    /**
     * adds CSS code to the header
     * @param string $code
     */
    public function addCSS($code) {
        $cssCode = new fily_ControlContainer('style');
        $cssCode->attributes->set('type',  'text/css');
        $cssCode->controls->add(new fily_Html($code));
        $this->CSSControls->add($cssCode);
    }

    /**
     * adds a javascript file to the head
     * @param <type> $file
     */
    public  function addJSFile($file) {
        $firstInclude = true; //it is the first include
        foreach($this->JSControls->getItems() as $jsFile) {
            if($jsFile->attributes->get('src') == $file) {
                $firstInclude = false; //already included
            }
        }


        if($firstInclude) {
            //add a javascript file to the header
            $script = new fily_Control('script');
            $script->attributes->set('type', 'text/javascript');
            $script->attributes->set('src', $file);
            $script->setEndTagRequired(true);
            $this->JSControls->add($script);
        }
    }


    /**
     * adds javascript code to the header
     * @param string $code
     */
    public function addJS($code) {
        $script = new fily_ControlContainer('script');
        $script->attributes->set('type', 'text/javascript');
        $script->controls->add(new fily_Html($code));
        $this->JSControls->add($script);
    }

    /**
     * Clears the stylesheet list.
     */
    public function clearCSS() {
        $this->CSSControls->clear();
    }

    /**
     * Clears the javascript list.
     */
    public function clearJS() {
        $this->JSControls->clear();
    }


    /**
     * Convert the cntrol into html.
     */
    public function toHtml() {
        $title = new fily_ControlContainer('title');
        $title->controls->add(new fily_Text($this->getTitle()));
        $this->headControls->add($title);
        $this->headControls->add($this->metaDataControls);
        $this->headControls->add($this->CSSControls);

        if($this->getJavascriptCorePath()!='') {
            // add the javascript core att the top from all js files
            $script = new fily_Control('script');
            $script->attributes->set('type', 'text/javascript');
            $script->attributes->set('src', $this->getJavascriptCorePath());
            $script->setEndTagRequired(true);
            $this->headControls->add($script);
        }

        $this->headControls->add($this->JSControls);

        $head = new fily_ControlContainer('head');
        $head->controls->add($this->headControls);

        $body = new fily_ControlContainer('body');
        $body->controls->add($this->controls);



        // create the body at first cause maybe in the toHtml() function some javascript will be added
        $bodyHtml = $body->toHtml();

        //add client code to the head
        $this->addJS(fily_ClientCodeManager::getPageClientCode());

        // now we can create the header
        $headHtml =  $head->toHtml();

        $docType = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
                "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">';

        return $docType . "\n<html xmlns=\"http://www.w3.org/1999/xhtml\">" .$headHtml . "\n" . $bodyHtml .'</html>';

    }

    /*
     * does nothing
    */
    public function prepare() {

    }
    /**
     * shortcut for toHtml()
     */
    public function __toString() {
        return $this->toHtml();
    }

    /**
     * sets the javascript core path
     * @param string $value
     */
    public function setJavascriptCorePath($value) {
        $this->javascriptCorePath = $value;
    }

    /**
     * returns the javascript core path
     * @return string
     */
    public function getJavascriptCorePath() {
        return $this->javascriptCorePath;
    }


    /**
     * this control can't have a id
     * it returns a empty string
     * @return string
     */
    public function getId() {
        return '';
    }
    /**
     * finds a control with the specific id
     * @param string $id
     * @return fily_ControlToHtml
     */
    public function getControlById($id) {
        return $this->controls->getControlById($id);
    }
  /**
     * system id
     * @var string
     */
    protected $sid;
         /**
     * system id
     * @return string
     */
    public function getSid(){
        return $this->sid;
    }

    /**
     * system id
     * @param string $sid
     */
    public function setSid($sid){
        $this->sid = $sid;
    }

    /**
     * finds a control with the specific system id
     * @param string $sid
     * @return fily_ControlToHtml
     */
    public function getControlBySid($sid) {
        return $this->controls->getControlBySid($sid);
    }


    public function XMLAddControl(fily_ControlToHtml $control) {
        $this->controls->add($control);
    }

    public function XMLAttributes(array $attributes, $value) {
        $value = trim($value);
        if(!empty($value)) {
            $this->controls->add(new fily_Text($value));
        }
        foreach($attributes as $key => $value) {
            switch ($key) {
                case 'title':
                    $this->setTitle($value);
                    break;
                case 'javascriptcorepath':
                    $this->setJavascriptCorePath($value);
                    break;
               case 'sid':
                    $this->setSid($value);
                    break;
                default:
                    throw new Exception('XML Convert : attribute "'. $key.'" not know for ' .  get_class($this));
                    break;
            }
        }
    }
    public function XMLLateBinding(fily_ControlToHtml $baseControl) {

    }
    public function XMLCallFunction($name, array $parameters,$innerValue, fily_ControlToHtml $innerControl = null) {
        switch($name) {
            case 'addcssfile':
                if(isset($parameters['file']))
                    $this->addCSSFile($parameters['file']);
                else
                    $this->addCSSFile($innerValue);
                break;
            case  'addcss':
                $this->addCSS($innerValue);
                break;
            case  'addjsfile':
                if(isset($parameters['file']))
                    $this->addJSFile($parameters['file']);
                else
                    $this->addJSFile($innerValue);
                break;
            case  'addjs':
                $this->addJS($innerValue);
                break;
            case 'addtohead':
                $this->addToHead($innerControl);

        }
    }
    public function find($expression) {
        $control = null;
        if(!fily_ExpressionHelper::isExpression($expression)) {
            //expression is an id
            $control = $this->getControlById($expression);
        }
        else {
            $expressionParts = fily_ExpressionHelper::getParts($expression) ;
            // first expression part is always empty
            if(count($expressionParts)>1) {
                switch ($expressionParts[1]) {
                    case 'after':
                        $control = fily_ExpressionHelper::after($expressionParts, $expression, $this->controls);
                        break;
                    case  'before':
                        $control = fily_ExpressionHelper::before($expressionParts, $expression, $this->controls);
                        break;
                    case 'first':
                        $control = fily_ExpressionHelper::first($expressionParts, $expression, $this->controls);
                        break;
                    case 'last':
                        $control = fily_ExpressionHelper::last($expressionParts, $expression,  $this->controls);
                        break;
                    case 'child':
                        $control = fily_ExpressionHelper::child($expressionParts, $expression, $this->controls);
                        break;
                    case 'root':
                    // i am the root
                        $control =$this;
                        $expression = fily_ExpressionHelper::create($expressionParts, 2);
                }
            }
            // found a control and have another expressions
            if($control!=null && !empty($expression)) {
                $control = $control->find($expression);
            }
        }
        return $control;
    }

    

}

?>